
#pragma warning(disable:4996)

#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <ctype.h>

#include "utils.h"

const int ArrayList::LAST_INDEX = -1;

ArrayList::ArrayList(int initCount)
{
	//printf("7,%x\r\n",this);
	mMaxCount = initCount <= 0 ? 2 : initCount;
	mCount = 0;
	mFirst = (void**)malloc( sizeof( void * ) * mMaxCount );
}

ArrayList :: ~ArrayList()
{
	//printf("~7,%x\r\n",this);
	free( mFirst );
	mFirst = NULL;
}

int ArrayList::getCount() const
{
	return mCount;
}

int ArrayList::append(void * value)
{
	if( NULL == value ) return -1;

	if( mCount >= mMaxCount ) {
		int maxcount = ( mMaxCount * 3 ) / 2 + 1;
		mFirst = (void**)realloc( mFirst, sizeof( void * ) * maxcount );
		assert( NULL != mFirst );
		if(mFirst==NULL)
			return 0;
		mMaxCount=maxcount;
		memset( mFirst + mCount, 0, ( mMaxCount - mCount ) * sizeof( void * ) );
	}

	mFirst[ mCount++ ] = value;

	return 0;
}

void * ArrayList::takeItem(int index)
{
	void * ret = NULL;

	if( LAST_INDEX == index ) index = mCount -1;
	if( index < 0 || index >= mCount ) return ret;

	ret = mFirst[ index ];

	mCount--;

	if( ( index + 1 ) < mMaxCount ) {
		memmove( mFirst + index, mFirst + index + 1,
			( mMaxCount - index - 1 ) * sizeof( void * ) );
	} else {
		mFirst[ index ] = NULL;
	}

	return ret;
}

const void * ArrayList::getItem(int index) const
{
	const void * ret = NULL;

	if( LAST_INDEX == index ) index = mCount - 1;
	if( index < 0 || index >= mCount ) return ret;

	ret = mFirst[ index ];

	return ret;
}

void ArrayList::clean()
{
	mCount = 0;
	memset( mFirst, 0, sizeof( void * ) * mMaxCount );
}

//-------------------------------------------------------------------

CircleQueue::CircleQueue(int count)
{
	//printf("8\r\n");
	mMaxCount = count+1;
	mEntries = (void**)malloc( sizeof( void * ) * mMaxCount );

	mHead = mTail = mCount = 0;
}

CircleQueue :: ~CircleQueue()
{
	//printf("~8\r\n");
	free (mEntries);
	mEntries = NULL;
}

void CircleQueue::push(void * item)
{
	if( mCount >= mMaxCount ) {
		int maxcount = ( mMaxCount * 3 ) / 2 + 1;
		void ** newEntries = (void**)malloc( sizeof( void * ) * maxcount );
		if(newEntries==NULL)
			return;
		mMaxCount=maxcount;
		unsigned int headLen = 0, tailLen = 0;
		if( mHead < mTail ) {
			headLen = mTail - mHead;
		} else {
			headLen = mCount - mTail;
			tailLen = mTail;
		}

		memcpy( newEntries, &( mEntries[ mHead ] ), sizeof( void * ) * headLen );
		if( tailLen ) {
			memcpy( &( newEntries[ headLen ] ), mEntries, sizeof( void * ) * tailLen );
		}

		mHead = 0;
		mTail = headLen + tailLen;

		free( mEntries );
		mEntries = newEntries;
	}

	mEntries[ mTail++ ] = item;
	mTail = mTail % mMaxCount;
	mCount++;
}

void * CircleQueue::pop()
{
	void * ret = NULL;

	if( mCount > 0 ) {
		ret = mEntries[ mHead++ ];
		mHead = mHead % mMaxCount;
		mCount--;
	}

	return ret;
}

void * CircleQueue::top()
{
	return mCount > 0 ? mEntries[ mHead ] : NULL;
}

int CircleQueue::getLength()
{
	return mCount;
}


//-------------------------------------------------------------------

BlockingQueue::BlockingQueue()
{
	mQueue = new CircleQueue();
}

BlockingQueue :: ~BlockingQueue()
{
	delete mQueue;
	mQueue=NULL;
}
void BlockingQueue::reserve(int len)
{
	
}
bool BlockingQueue::push(void * item)
{
	std::unique_lock<mutex> lock(mtx);
	mQueue->push( item );
	cond.notify_one();
	return true;
}

void * BlockingQueue::pop()
{
	void * ret = NULL;
	std::unique_lock<mutex> lock(mtx);
	if( mQueue->getLength() == 0 ) {
		cond.wait(lock);
	}
	ret = mQueue->pop();
	return ret;
}

void * BlockingQueue::top()
{
	void * ret = NULL;
	std::unique_lock<mutex> lock(mtx);
	ret = mQueue->top();
	return ret;
}

int BlockingQueue::getLength()
{
	int len = 0;
	std::unique_lock<mutex> lock(mtx);
	len = mQueue->getLength();
	return len;
}

//-------------------------------------------------------------------

SafeQueue::SafeQueue(int count)
{
	maxcount=count;
	mQueue = new CircleQueue(count);
	sp_thread_semaphore_init( &mSem, 0, count);
}

SafeQueue :: ~SafeQueue()
{
	delete mQueue;
	sp_thread_semaphore_destroy( &mSem );
}
void SafeQueue::reserve(int len)
{
	
}
bool SafeQueue::push(void * item)
{
	std::unique_lock<mutex> lock(mtx);
	if(mQueue->getLength()>=maxcount)
	{
		return false;
	}
	mQueue->push( item );
	if( sp_thread_semaphore_post(&mSem)!=0)
	{
		return false;
	}
	return true;
}

void * SafeQueue::pop()
{
	if(sp_thread_semaphore_wait(&mSem)!=0)
		return NULL;
	void * ret = NULL;
	std::unique_lock<mutex> lock(mtx);
	ret = mQueue->pop();
	return ret;
}

void * SafeQueue::top()
{
	void * ret = NULL;
	std::unique_lock<mutex> lock(mtx);
	ret = mQueue->top();
	return ret;
}

int SafeQueue::getLength()
{
	int len = 0;
	std::unique_lock<mutex> lock(mtx);
	len = mQueue->getLength();
	return len;
}

//-------------------------------------------------------------------

int strtok( const char * src, int index, char * dest, int len,
		char delimiter, const char ** next )
{
	int ret = 0;

	const char * pos1 = src, * pos2 = NULL;

	if( isspace( delimiter ) ) delimiter = 0;

	for( ; isspace( *pos1 ); ) pos1++;

	for ( int i = 0; i < index; i++ ) {
		if( 0 == delimiter ) {
			for( ; '\0' != *pos1 && !isspace( *pos1 ); ) pos1++;
			if( '\0' == *pos1 ) pos1 = NULL;
		} else {
			pos1 = strchr ( pos1, delimiter );
		}
		if ( NULL == pos1 ) break;

		pos1++;
		for( ; isspace( *pos1 ); ) pos1++;
	}

	*dest = '\0';
	if( NULL != next ) *next = NULL;

	if ( NULL != pos1 && '\0' != * pos1 ) {
		if( 0 == delimiter ) {
			for( pos2 = pos1; '\0' != *pos2 && !isspace( *pos2 ); ) pos2++;
			if( '\0' == *pos2 ) pos2 = NULL;
		} else {
			pos2 = strchr ( pos1, delimiter );
		}
		if ( NULL == pos2 ) {
			strncpy ( dest, pos1, len );
			if ( ((int)strlen(pos1)) >= len ) ret = -2;
		} else {
			if( pos2 - pos1 >= len ) ret = -2;
			len = ( pos2 - pos1 + 1 ) > len ? len : ( pos2 - pos1 + 1 );
			strncpy( dest, pos1, len );

			for( pos2++; isspace( *pos2 ); ) pos2++;
			if( NULL != next && '\0' != *pos2 ) *next = pos2;
		}
	} else {
		ret = -1;
	}

	dest[ len - 1 ] = '\0';
	len = strlen( dest );

	// remove tailing space
	for( ; len > 0 && isspace( dest[ len - 1 ] ); ) len--;
	dest[ len ] = '\0';

	return ret;
}

char * strlcpy( char * dest, const char * src, int n )
{
	strncpy( dest, src, n );
	dest[ n - 1 ] = '\0';

	return dest;
}

